.NET Framework 2.0で、XmlWriterを使ってXML文書を書き出す場合には、XmlTextWriterクラスを使わず、XmlWriter.Createメソッドでインスタンスを取得する方法が推奨されています。
また、このメソッドの引数に指定できるXmlWriterSettingsメソッドは、きめ細かい動作のオプションを指定することを可能としています。
このうちのXmlWriterSettings.CloseOutputプロパティは、XmlWriterのCloseメソッドを呼んだときに、元になるストリームも閉じるかを指定します。これがfalseの場合、XmlWriterをCloseしたあと、ストリームに何かを書き足すことが可能になります。たとえば、MIMEマルチパートの電子メール本文を書き出す場合などには便利そうですね。
このプロパティの既定値はfalseです。つまり、Closeメソッドを呼び出しても、元になるストリームは閉じられません。
以上が前提です。
ファイル名を指定するCreateメソッド §
XmlWriter.Createメソッドには、引数によって様々なバリエーションがあります。その多くは、XmlWriterSettingsオブジェクトを渡すバリエーションと省略して既定値で使うバリエーションが存在します。
さて、ここでファイル名のみを指定してそれに対して出力するXmlWriterオブジェクトを生成するバリエーションについて見ていきましょう。
以下のように使うわけです。
XmlWriter writer = XmlWriter.Create(@"c:\\test.xml");
writer.WriteElementString("test", "data");
writer.Close();
さて、ここで注意してください。
このケースでは、明示的にXmlWriterSettingsを渡していません。おそらく、既定値で使われていることが予想されます。
そして、XmlWriterSettings.CloseOutputプロパティの既定値はfalseです。
ということは、Closeメソッドを呼び出しても、書き込みに使われるストリームは閉じられません。
しかし、このプログラムでは、ストリームを閉じるコードが含まれません。というか、そもそもXmlWriterというのは抽象的なクラスなので、ストリームを取得する手段が提供されていません。
(もちろん、抽象的なクラスのインスタンスは作成できないので、実は取得されているのは非公開クラスらしきSystem.Xml.XmlWellFormedWriterクラスのインスタンス)
ということは、ファイル名のみを指定するCreateメソッドを使うと永遠にファイルを閉じることができない?
つまり、ファイル名のみを指定するCreateメソッドには存在意義がない?
実はそうではないらしい §
実はXmlWriterSettings.CloseOutputプロパティの既定値はfalseだという記述は必ずしも正確ではないようです。
というのは、実はファイル名のみを指定するCreateメソッドを使うと、このプロパティの値はtrueになってしまうからです。
検証プログラムで確かめてみました。
検証プログラム §
.NET Framework 2.0+C#, Visual Studio 2005で作成
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
namespace ConsoleApplication75
{
class Program
{
static void Main(string[] args)
{
XmlWriter writer = XmlWriter.Create(@"c:\\test.xml");
Console.WriteLine("writer.Settings.CloseOutput={0}",
writer.Settings.CloseOutput);
Console.WriteLine(writer.ToString());
writer.WriteElementString("test", "data");
writer.Close();
FileStream stream = new FileStream(@"c:\\test.xml",
FileMode.Create);
XmlWriter writer2 = XmlWriter.Create(stream);
Console.WriteLine("writer2.Settings.CloseOutput={0}",
writer2.Settings.CloseOutput);
Console.WriteLine(writer2.ToString());
writer2.WriteElementString("test", "data");
writer2.Close();
// あ、streamをCloseするのを忘れているぞ…… (汗
}
}
}
実行結果 §
writer.Settings.CloseOutput=True
System.Xml.XmlWellFormedWriter
writer2.Settings.CloseOutput=False
System.Xml.XmlWellFormedWriter
CloseOutputプロパティの値は自動的に補正される §
結果を見て分かる通り、ファイル名だけを渡した場合と、ストリームだけを渡した場合では、CloseOutputプロパティの値は異なっています。
つまり、後からストリームを閉じることができないケースについては、自動的にCloseOutputプロパティの値がtrueに補正されるようです。
つまり、ファイル名のみを指定するCreateメソッドには存在意義はあります。
XmlWellFormedWriterって何だろう? §
googleさんに質問しても、19件しかヒットしない謎のクラスです。
Createというファクトリ・メソッドで詳細を隠蔽したのだから触るな……、ということでしょうが、たぶんそれで済まないこともあるでしょう。